{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<Center><h3> Part 1 : Alternating Least Square(ALS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Import Section "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import time\n",
    "import numpy as np\n",
    "import random\n",
    "import scipy \n",
    "from scipy import sparse\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.sparse.linalg import svds\n",
    "from functions import *\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Explore Data "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_data(filename=\"u.data\" , small_data=True):\n",
    "    \"\"\"\n",
    "    This function returns :\n",
    "        R : the matrix user-item containing the ratings\n",
    "        mask : matrix is equal to 1 if a score existes and 0 otherwise\n",
    "    \"\"\"\n",
    "\n",
    "    # Use this line to test on u.data (100K dataset)\n",
    "    data = np.loadtxt(filename, dtype=int)\n",
    "    \n",
    "    # Use this line to test on ratings.csv (20M dataset) \n",
    "#     data = np.loadtxt(open(filename, \"rb\"), delimiter=\",\", skiprows=1)\n",
    "    \n",
    "\n",
    "    \n",
    "    \n",
    "    R = sparse.csr_matrix((data[:, 2], (data[:, 0]-1, data[:, 1]-1)),dtype=float)\n",
    "    mask = sparse.csr_matrix((np.ones(data[:, 2].shape),(data[:, 0]-1, data[:, 1]-1)), dtype=bool )\n",
    "\n",
    "    # take a small part of the whole data for testing \n",
    "    if small_data is True:\n",
    "        R = (R[0:100, 0:100].copy())\n",
    "        mask = (mask[0:100, 0:100].copy())\n",
    "        \n",
    "        \n",
    "    return R.toarray(), mask.toarray()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "R, mask = load_data(filename='u.data', small_data=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5.,  3.,  4., ...,  4.,  3.,  5.],\n",
       "       [ 4.,  0.,  0., ...,  0.,  0.,  5.],\n",
       "       [ 0.,  0.,  0., ...,  0.,  0.,  0.],\n",
       "       ..., \n",
       "       [ 0.,  0.,  0., ...,  0.,  0.,  0.],\n",
       "       [ 4.,  0.,  3., ...,  5.,  0.,  5.],\n",
       "       [ 0.,  0.,  0., ...,  0.,  0.,  0.]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "R"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ True,  True,  True, ...,  True,  True,  True],\n",
       "       [ True, False, False, ..., False, False,  True],\n",
       "       [False, False, False, ..., False, False, False],\n",
       "       ..., \n",
       "       [False, False, False, ..., False, False, False],\n",
       "       [ True, False,  True, ...,  True, False,  True],\n",
       "       [False, False, False, ..., False, False, False]], dtype=bool)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mask"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The gradient of the objective function is given by : \n",
    "\n",
    "\n",
    "$$ \\bigtriangledown f (P,Q) = \\begin{pmatrix}\n",
    "                    - Q^T\\left[1_Ko(R - QP)\\right] + \\rho P \\\\ \n",
    "                    - \\left[1_Ko (R - QP)\\right] P^T + \\rho Q\n",
    "                    \\end{pmatrix}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "** Initialize the matrix P and Q  **"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "rho = 0.2 # regularization parameter\n",
    "C = 6 # projection space\n",
    "U,S,Vt = scipy.sparse.linalg.svds(R, k=6) #SVD decomposition\n",
    "Q0 = U\n",
    "P0 = Vt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** Linear Search to find the minimum using the Armijo–Goldstein condition **"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def search_gamma(func, P, c1, c2):\n",
    "    n = 0\n",
    "    gamma = c2 * (c1 ** n)\n",
    "    P1 = P - gamma * func(P)[1]\n",
    "    while func(P1)[0] >= func(P)[0] + np.vdot(func(P)[1], (P1-P)) + 1. / ( 2 * gamma) * (np.linalg.norm(P1-P) ** 2) :\n",
    "        n += 1\n",
    "        gamma = c2 * (c1 ** n)\n",
    "        P1 = P - gamma * func(P)[1]\n",
    "    return c2 * (c1 ** (n-1))\n",
    "\n",
    "\n",
    "def grad_line_search(func, P0, epsilon): \n",
    "    P = P0\n",
    "    max_iter = 0\n",
    "    gamma = 0.5\n",
    "    while (np.linalg.norm(func(P)[1]) > epsilon and max_iter < 300):\n",
    "        c2 = gamma\n",
    "        gamma = search_gamma(func ,P, 0.5, 0.5)\n",
    "        P = P - gamma * func(P)[1]\n",
    "        max_iter += 1\n",
    "    return P, max_iter "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running time : 0.02 s \n",
      "Number of iterations : 8\n"
     ]
    }
   ],
   "source": [
    "t = time()\n",
    "P_star, n = grad_line_search(lambda P : objective(P, Q0, R, mask, rho), Vt, 1)\n",
    "\n",
    "print(\"Running time : %0.2f s \\nNumber of iterations : %d\"%((time()-t),n))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** ALS Algorithm **"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ALS(P0, Q0, mask, rho, eps, max_iter):\n",
    "    Q = Q0\n",
    "    P = P0\n",
    "    k = 0\n",
    "    \n",
    "    val, grad_P = objective_P(P0, Q0, R, mask, rho)\n",
    "    _, grad_Q = objective_Q(P0, Q0, R, mask, rho)\n",
    "    \n",
    "    list_obj = []\n",
    "    list_norm_P = []\n",
    "    list_norm_Q = []\n",
    "\n",
    "    list_obj.append(val)\n",
    "    list_norm_P.append(np.linalg.norm(grad_P))\n",
    "    list_norm_Q.append(np.linalg.norm(grad_Q))\n",
    "    \n",
    "    while (np.linalg.norm(grad_P) > eps or np.linalg.norm(grad_Q) > eps) and k < max_iter:\n",
    "        \n",
    "        # minimizing P and Q using a line search \n",
    "        P, _ = grad_line_search(lambda P : objective_P(P, Q, R, mask, rho), P, eps)\n",
    "        Q, _ = grad_line_search(lambda Q : objective_Q(P, Q, R, mask, rho), Q, eps)\n",
    "        \n",
    "        val, grad_P = objective_P(P, Q, R, mask, rho)\n",
    "        _, grad_Q = objective_Q(P, Q, R, mask, rho)\n",
    "        k += 1\n",
    "        \n",
    "        list_obj.append(val)\n",
    "        list_norm_P.append(np.linalg.norm(grad_P))\n",
    "        list_norm_Q.append(np.linalg.norm(grad_Q))\n",
    "        \n",
    "        if k == 1 or k % 10 == 0:\n",
    "            print(\"iteration = %d\"%k)\n",
    "            print(\"Norm of grad_P = %0.5f \"%np.linalg.norm(grad_P))\n",
    "            print(\"Norm of grad_Q = %0.5f \"%np.linalg.norm(grad_Q))\n",
    "\n",
    "    return P, Q, max_iter, list_obj, list_norm_P, list_norm_Q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Test the ALS function **"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iteration = 1\n",
      "Norm of grad_P = 34.23989 \n",
      "Norm of grad_Q = 44.61366 \n",
      "iteration = 10\n",
      "Norm of grad_P = 13.47818 \n",
      "Norm of grad_Q = 3.65117 \n",
      "iteration = 20\n",
      "Norm of grad_P = 10.15628 \n",
      "Norm of grad_Q = 0.68936 \n",
      "iteration = 30\n",
      "Norm of grad_P = 8.45526 \n",
      "Norm of grad_Q = 0.37579 \n",
      "iteration = 40\n",
      "Norm of grad_P = 7.18822 \n",
      "Norm of grad_Q = 0.09654 \n",
      "iteration = 50\n",
      "Norm of grad_P = 6.49649 \n",
      "Norm of grad_Q = 0.55601 \n",
      "iteration = 60\n",
      "Norm of grad_P = 5.92887 \n",
      "Norm of grad_Q = 0.46163 \n",
      "iteration = 70\n",
      "Norm of grad_P = 5.26699 \n",
      "Norm of grad_Q = 0.20904 \n",
      "iteration = 80\n",
      "Norm of grad_P = 4.80220 \n",
      "Norm of grad_Q = 0.09966 \n",
      "iteration = 90\n",
      "Norm of grad_P = 4.33362 \n",
      "Norm of grad_Q = 0.09841 \n",
      "iteration = 100\n",
      "Norm of grad_P = 3.94026 \n",
      "Norm of grad_Q = 0.09804 \n",
      "iteration = 110\n",
      "Norm of grad_P = 3.60102 \n",
      "Norm of grad_Q = 0.09145 \n",
      "iteration = 120\n",
      "Norm of grad_P = 3.32327 \n",
      "Norm of grad_Q = 0.15757 \n",
      "iteration = 130\n",
      "Norm of grad_P = 3.11901 \n",
      "Norm of grad_Q = 0.28346 \n",
      "iteration = 140\n",
      "Norm of grad_P = 2.85846 \n",
      "Norm of grad_Q = 0.09889 \n",
      "iteration = 150\n",
      "Norm of grad_P = 2.54714 \n",
      "Norm of grad_Q = 0.09956 \n",
      "iteration = 160\n",
      "Norm of grad_P = 2.28206 \n",
      "Norm of grad_Q = 0.09821 \n",
      "iteration = 170\n",
      "Norm of grad_P = 2.08392 \n",
      "Norm of grad_Q = 0.09925 \n",
      "iteration = 180\n",
      "Norm of grad_P = 1.88370 \n",
      "Norm of grad_Q = 0.09959 \n",
      "iteration = 190\n",
      "Norm of grad_P = 1.69063 \n",
      "Norm of grad_Q = 0.09421 \n",
      "iteration = 200\n",
      "Norm of grad_P = 1.56467 \n",
      "Norm of grad_Q = 0.09481 \n",
      "iteration = 210\n",
      "Norm of grad_P = 1.41194 \n",
      "Norm of grad_Q = 0.09666 \n",
      "iteration = 220\n",
      "Norm of grad_P = 1.27709 \n",
      "Norm of grad_Q = 0.09958 \n",
      "iteration = 230\n",
      "Norm of grad_P = 1.17261 \n",
      "Norm of grad_Q = 0.09997 \n",
      "iteration = 240\n",
      "Norm of grad_P = 1.03065 \n",
      "Norm of grad_Q = 0.09900 \n",
      "iteration = 250\n",
      "Norm of grad_P = 0.95691 \n",
      "Norm of grad_Q = 0.09865 \n",
      "iteration = 260\n",
      "Norm of grad_P = 0.87574 \n",
      "Norm of grad_Q = 0.09408 \n",
      "iteration = 270\n",
      "Norm of grad_P = 0.76517 \n",
      "Norm of grad_Q = 0.09571 \n",
      "iteration = 280\n",
      "Norm of grad_P = 0.70438 \n",
      "Norm of grad_Q = 0.09761 \n",
      "iteration = 290\n",
      "Norm of grad_P = 0.63906 \n",
      "Norm of grad_Q = 0.09341 \n",
      "iteration = 300\n",
      "Norm of grad_P = 0.57972 \n",
      "Norm of grad_Q = 0.09264 \n"
     ]
    }
   ],
   "source": [
    "rho = 0.2 # regularization parameter\n",
    "C = 6 # projection space \n",
    "U,S,Vt = scipy.sparse.linalg.svds(R, k=6) #SVD decomposition\n",
    "Q0 = U\n",
    "P0 = Vt\n",
    "eps = .1 # value of epsilon\n",
    "max_iter = 300 # maximum of iterations\n",
    "\n",
    "# call the Als function\n",
    "P, Q, n, list_obj, list_norm_P, list_norm_Q = ALS(Vt, U, mask, rho, eps, max_iter)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a61d9f9be0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(8,5))\n",
    "\n",
    "plt.plot(list_obj)\n",
    "plt.xlabel(\"#iterations\", fontsize=14)\n",
    "plt.ylabel(\"$Objective$\", fontsize=14)\n",
    "plt.title('The value of the objective function Vs the number of iterations')\n",
    "plt.grid(True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a61e132e80>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15,5))\n",
    "\n",
    "plt.subplot(121)\n",
    "plt.plot(list_norm_P)\n",
    "plt.xlabel(\"#iterations\", fontsize=14)\n",
    "plt.ylabel(\"$Norm$\", fontsize=14)\n",
    "plt.title('Norm of the gradient of P Vs the number of iterations')\n",
    "plt.grid(True)\n",
    "\n",
    "\n",
    "plt.subplot(122)\n",
    "plt.plot(list_norm_Q)\n",
    "plt.xlabel(\"#iterations\", fontsize=14)\n",
    "plt.ylabel(\"$Norm$\", fontsize=14)\n",
    "plt.title('Norm of the gradient of Q Vs the number of iterations')\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Relative error : 10.801425\n",
      "Total objective f(P,Q) = 269.09040 \n"
     ]
    }
   ],
   "source": [
    "relative_error = np.linalg.norm(mask*(R - np.dot(Q, P))) / np.linalg.norm(R) * 100\n",
    "\n",
    "print(\"Relative error : %f\"%relative_error)\n",
    "print(\"Total objective f(P,Q) = %0.5f \"%(objective(P, Q, R, mask, rho)[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** Recommandation ** "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In order to find the movie that we'll recommand to the user n° u, we have to consider the decomposition $ R = QP$.\n",
    "\n",
    "In fact, by multiplying the $u^{th}$ row of Q by the matrix P, we obtain a vector r of size $ I$ x $ 1$ that contains all the estimated ratings of movies for this user u.   \n",
    "\n",
    "Now, we only need to consider the highest score and take its index (which correspond to the recommanded movie), however we shoudn't forget that we have to avoid recommanding a movie that the user had already seen, that's why we need to multiply our vector r by the opposite of the mask. \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** What recommanding to the user n° 45 ?** "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "We recommand to the user n° 45 the movie n°  31\n",
      "The rating of this movie is : 4.729 \n"
     ]
    }
   ],
   "source": [
    "u = 45\n",
    "r = np.dot(Q[u,:], P)\n",
    "\n",
    "r = r * (1 - mask[u,:])\n",
    "\n",
    "movie_index = np.argmax(r)\n",
    "print(\"We recommand to the user n° %s the movie n°  %d\"%(u,movie_index))\n",
    "print (\"The rating of this movie is : %0.3f \"%r[movie_index])"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
